/**
 * @since 2024-12-06 全局参数
 */
const DEV = false, SCORE_KEY = "leetcode-score-v0.0.9", LEVEL_KEY = "leetcode-level", TRY_TIMES = 256;
let CN_DOMAIN = true;

ConsoleLog("版本 0.0.9");
// console.log = function() {};
// console.log(chrome.i18n.getMessage("extension_name"), "0.0.9");

$(document).ready(function(){
    /**
     * @since 2024-12-06 是否英文国际站
     */
    if(window.location.host == "leetcode.com") CN_DOMAIN = false;

    /**
     * @since 2024-12-06 主函数
     */
    Main();

    /**
     * @since 2024-12-06 截图用
     */
    // setTimeout(function(){
    //     $('.flex.items-start.justify-between.gap-4').css("margin-top", "200px");
    //     $('.flex.items-start.justify-between.gap-4').css("margin-left", "50px");
    //     $('.flex.gap-1').css("margin-bottom", "300px");
    //     $('.flex.gap-1').css("margin-left", "50px");
    //
    //     /**
    //      * @since 2024-12-06 等级分div
    //      */
    //     // $('#cn-leetcode-level').trigger('mouseenter');
    // }, 3000);
});

/**
 * @title 入口函数
 * @author start2004
 * @since 2024-07-25
 */
function Main(){
    /**
     * @since 2024-07-25 获取url的题目标题
     */
    let leetcodeTitle = GetTitle();
    if(!leetcodeTitle) return ;
    ConsoleLog("标题", leetcodeTitle);

    /**
     * @since 2024-07-25 设置题目的难度分
     */
    SetScore(leetcodeTitle);

    /**
     * @since 2024-09-04 设置题目的等级
     */
    SetLevel(leetcodeTitle);
}

/**
 * @title 返回URL中题目标题
 * @author start2004
 * @since 2024-07-25
 *
 * @return {string}
 */
function GetTitle(){
    /**
     * @since 2024-07-23 匹配url中题目标题
     * https://leetcode.cn/problems/two-sum/description/
     */
    let leetcodeMatch = window.location.href.match(/\/problems\/(.*?)\//);
    let leetcodeTitle = '';
    if (leetcodeMatch) {
        leetcodeTitle = leetcodeMatch[1];
    } else {
        ConsoleLog("匹配LeetCode题目标题失败", window.location.href);
    }
    return leetcodeTitle;
}

/**
 * @title 设置-题目难度分
 * @author start2004
 * @since 2024-07-25
 *
 * @param {string} title
 */
async function SetScore(title){
    /**
     * @since 2024-09-04 读取缓存
     */
    let scoreObject = await GetStorage(SCORE_KEY), scoreData = {};
    // ConsoleLog(scoreObject);

    /**
     * @since 2024-09-04 无缓存数据
     */
    if(scoreObject === undefined){
        /**
         * @since 2024-09-04 从缓存文件读取数据，并格式化
         */
        ConsoleLog("难度分，无缓存数据，读取文件score.json");
        scoreData = await FetchJson(chrome.runtime.getURL("../json/score.json"));
        scoreData = FormatScoreData(scoreData);
    } else {
        scoreData = scoreObject.data;
        ConsoleLog("难度分，数据时间", scoreObject.date);
    }

    /**
     * @since 2024-09-04 获取题目相关数据
     */
    let problemObject = {};
    if(!scoreData.hasOwnProperty(title)) {
        ConsoleLog("难度分，没有找到", title);
    } else {
        problemObject = scoreData[title];
        ConsoleLog("难度分，单个数据", problemObject);
    }

    /**
     * @since 2024-09-04 显示题目的难度分
     */
    if(Object.keys(problemObject).length > 0){
        ShowScore(problemObject, TRY_TIMES);
    } else {}

    /**
     * @since 2024-09-04 更新数据
     */
    if(scoreObject === undefined || scoreObject.time+86400*1000 < Date.now()){
    // if(scoreObject === undefined || scoreObject.time+1000 < Date.now()){
        /**
         * @since 2024-09-04 更新成功，则再执行一次显示难度分
         */
        let updateResult = await UpdateScore();
        if(updateResult && (Object.keys(problemObject).length == 0)) SetScore(title);
    } else {}
}

/**
 * @title 格式化难度分数据
 * @author start2004
 * @since 2024-07-25
 *
 * @param {object} data
 * @return {object}
 */
function FormatScoreData(data){
    let json = {}
    for(let i in data){
        let d = data[i];

        let contestId = parseInt(d["ContestID_en"].split(" ")[2]);
        let biweekly = (d["ContestID_en"].split(" ")[0] == "Biweekly") ? true : false;

        json[d['TitleSlug']] = {
            "Rating": parseInt(d["Rating"]),
            "TitleSlug": d["TitleSlug"],
            "ContestSlug": d["ContestSlug"],
            "ProblemIndex": d["ProblemIndex"],
            "ContestID": contestId,
            "biweekly": biweekly,
        };
    }
    return json;
}

/**
 * @title 显示题目难度分数
 * @author start2004
 * @since 2024-07-23
 *
 * @param {object} problemObject 难度分对象
 * @param {int} times 迭代次数
 */
function ShowScore(problemObject, times){
    if((Object.keys(problemObject).length == 0) || (times == 0)) return ;
    // ConsoleLog("times", times);

    /**
     * @since 2024-07-23 存在分数div
     */
    if(AddDiv()){
        if($("#cn-leetcode-score").html() == ""){
            /**
             * @since 2024-07-23 题目难度分数
             */
            let score = problemObject["Rating"];

            /**
             * @since 2024-07-25 题目难度
             */
            let difficltyClass = '';
            if($(".text-difficulty-easy").length){
                difficltyClass = "text-difficulty-easy";
            } else if($(".text-difficulty-medium").length){
                difficltyClass = "text-difficulty-medium";
            } else if($(".text-difficulty-hard").length){
                difficltyClass = "text-difficulty-hard";
            } else {}

            /**
             * @since 2024-09-04 中文版和英文版，难度分和竞赛链接地址
             */
            let difficltyHtml, contestHtml, contestName;

            /**
             * @since 2024-12-06 中国站
             */
            if(CN_DOMAIN){
                difficltyHtml = "难度分 "+ score;

                if(problemObject["biweekly"]){
                    contestName = "第"+ problemObject["ContestID"] +"场双周赛";
                } else {
                    contestName = "第"+ problemObject["ContestID"] +"场周赛";
                }
            } else {
                /**
                 * @since 2024-12-06 英文国际站
                 */
                difficltyHtml = "Rating "+ score;

                if(problemObject["biweekly"]){
                    contestName = "Biweekly Contest "+ problemObject["ContestID"] +"th ";
                } else {
                    contestName = "Weekly Contest "+ problemObject["ContestID"] +"th ";
                }
            }
            contestHtml = "<a href='/contest/"+ problemObject["ContestSlug"] +"' target='_blank' title='"+ chrome.i18n.getMessage("contest_link_title") +"'>"+ contestName + problemObject["ProblemIndex"] +"</a>";

            $("#cn-leetcode-score").html("<svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"lightbulb\" style='left:0.7rem' class=\"svg-inline--fa fa-lightbulb absolute top-1/2 -translate-x-1/2 -translate-y-1/2 "+ difficltyClass +"\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"><path fill=\"currentColor\" d=\"M297.2 248.9C311.6 228.3 320 203.2 320 176c0-70.7-57.3-128-128-128S64 105.3 64 176c0 27.2 8.4 52.3 22.8 72.9c3.7 5.3 8.1 11.3 12.8 17.7l0 0c12.9 17.7 28.3 38.9 39.8 59.8c10.4 19 15.7 38.8 18.3 57.5H109c-2.2-12-5.9-23.7-11.8-34.5c-9.9-18-22.2-34.9-34.5-51.8l0 0 0 0c-5.2-7.1-10.4-14.2-15.4-21.4C27.6 247.9 16 213.3 16 176C16 78.8 94.8 0 192 0s176 78.8 176 176c0 37.3-11.6 71.9-31.4 100.3c-5 7.2-10.2 14.3-15.4 21.4l0 0 0 0c-12.3 16.8-24.6 33.7-34.5 51.8c-5.9 10.8-9.6 22.5-11.8 34.5H226.4c2.6-18.7 7.9-38.6 18.3-57.5c11.5-20.9 26.9-42.1 39.8-59.8l0 0 0 0 0 0c4.7-6.4 9-12.4 12.7-17.7zM192 128c-26.5 0-48 21.5-48 48c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-44.2 35.8-80 80-80c8.8 0 16 7.2 16 16s-7.2 16-16 16zm0 384c-44.2 0-80-35.8-80-80V416H272v16c0 44.2-35.8 80-80 80z\"></path></svg><span style='margin-left: 12px' class='"+ difficltyClass +"'>"+ difficltyHtml +"</span>");
            $("#cn-leetcode-score").show();

            $("#cn-leetcode-contest").html(contestHtml);
            $("#cn-leetcode-contest").show();
            ConsoleLog("难度分，加载成功");
        } else {
            ConsoleLog("难度分，存在");
        }
    } else {
        /**
         * @since 2024-07-24 页面未加载成功，稍后再试
         */
        ConsoleLog("难度分，未加载成功，等待");
        // setTimeout(ShowScore, 200, problemObject, times-1);
    }

    /**
     * @since 2024-10-09 leetcode页面出现重载的情况
     * @since 2024-10-09 可能中英文切换
     */
    setTimeout(ShowScore, 200, problemObject, times-1);
}

/**
 * @title 添加显示的div
 * @author start2004
 * @since 2024-09-04
 */
function AddDiv(){
    /**
     * @since 2024-07-23 添加div
     */
    if($('#cn-leetcode-score').length == 0){
        $('div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.flex.gap-1').first().prepend('<span id="cn-leetcode-score" class="relative inline-flex items-center justify-center text-caption px-2 py-1 gap-1 rounded-full bg-fill-secondary cursor-pointer transition-colors hover:bg-fill-primary hover:text-text-primary text-sd-secondary-foreground hover:opacity-80" style="display: none"></span><span id="cn-leetcode-contest" class="relative inline-flex items-center justify-center text-caption px-2 py-1 gap-1 rounded-full bg-fill-secondary cursor-pointer transition-colors hover:bg-fill-primary hover:text-text-primary text-sd-secondary-foreground hover:opacity-80" style="display: none"></span><span id="cn-leetcode-level" class="relative inline-flex items-center justify-center text-caption px-2 py-1 gap-1 rounded-full bg-fill-secondary cursor-pointer transition-colors hover:bg-fill-primary hover:text-text-primary text-sd-secondary-foreground hover:opacity-80" style="display: none"></span>');
        return $('#cn-leetcode-score').length>0;
    } else {
        return true;
    }
}

/**
 * @title 更新难度分数据
 * @author start2004
 * @since 2024-07-25
 */
async function UpdateScore(){
    /**
     * @since 2024-09-04 获取数据
     */
    const scoreUrl = "https://zerotrac.github.io/leetcode_problem_rating/data.json";
    let ScoreData = await FetchJson(scoreUrl);
    if(ScoreData === null) return false;
    ScoreData = FormatScoreData(ScoreData);

    /**
     * @since 2024-09-04 更新缓存
     */
    const ScoreObject = {
        "date": Date(),
        "time": Date.now(),
        "data": ScoreData
    };
    await SetStorage(SCORE_KEY, ScoreObject);
    ConsoleLog("难度分，数据更新成功");
    return true;
}

/**
 * @title 设置题目的等级
 * @author start2004
 * @since 2024-09-04
 *
 * @param {string} title 题目标题
 */
async function SetLevel(title){
    /**
     * @since 2024-09-04 读取缓存
     */
    let levelObject = await GetStorage(LEVEL_KEY), levelData = {};
    // ConsoleLog("等级", levelObject);

    /**
     * @since 2024-09-04 无缓存数据
     */
    if(levelObject === undefined){
        /**
         * @since 2024-09-04 从缓存文件读取数据，并格式化
         */
        ConsoleLog("等级，无缓存数据，读取文件level.json");
        levelData = await FetchJson(chrome.runtime.getURL("../json/level.json"));
    } else {
        levelData = levelObject.data;
        ConsoleLog("等级，数据时间", levelObject.date);
    }
    // ConsoleLog("等级", levelData);

    /**
     * @since 2024-09-04 获取题目相关数据
     */
    let problemLevel = null;
    if(!levelData.hasOwnProperty(title)) {
        ConsoleLog("等级，没有找到", title);
    } else {
        problemLevel = levelData[title];
        ConsoleLog("等级，数值", problemLevel);
    }

    /**
     * @since 2024-09-04 显示题目的难度分
     */
    if(problemLevel !== null){
        ShowLevel(problemLevel, TRY_TIMES);
    } else {}

    /**
     * @since 2024-09-04 更新数据
     */
    if(levelObject === undefined || levelObject.time+86400*1000 < Date.now()){
    // if(levelObject === undefined || levelObject.time+1000 < Date.now()){
        /**
         * @since 2024-09-04 更新成功，则再执行一次显示难度分
         */
        let updateResult = await UpdateLevel();
        if(updateResult && (problemLevel === null)) SetLevel(title);
    } else {}
}

/**
 * @title 显示题目等级数据
 * @author start2004
 * @since 2024-09-04
 *
 * @param {int} problemLevel 题目等级数字
 * @param {int} times
 */
function ShowLevel(problemLevel, times){
    if((Object.keys(problemLevel).length == 0) || (times == 0)) return ;

    /**
     * @since 2024-07-23 存在div
     */
    if(AddDiv()){
        if($("#cn-leetcode-level").html() == ""){
            if($("#cn-leetcode-remark").length == 0){
                let remarkDiv = '<div id="cn-leetcode-remark" style="position: fixed; cursor: pointer; z-index: 99998888; display: none; border-radius: 20px; padding: 8px 20px 8px 15px; opacity: 1; background-color: #F0F0F0; color: #121212"></div>';
                $("body").prepend(remarkDiv);
            } else {}

            /**
             * @since 2024-09-04 中文版和英文版
             */
            let levelHtml, remarkArray, remarkHtmlArray = new Array();
            if(CN_DOMAIN){
                levelHtml = "等级 "+ problemLevel;
            } else {
                levelHtml = "Level "+ problemLevel;
            }
            remarkArray = new Array(
                new Array(chrome.i18n.getMessage("level"), chrome.i18n.getMessage("data_structures")),
                new Array("1-3", chrome.i18n.getMessage("master")),
                new Array("4-7", chrome.i18n.getMessage("proficient")),
                new Array(">=8", chrome.i18n.getMessage("expert")),
            );

            /**
             * @since 2024-09-04 备注描述
             */
            for(let i in remarkArray){
                remarkHtmlArray.push('<li><div style="width: 60px; display: inline-block; text-align: center">'+ remarkArray[i][0] +'</div><div style="margin-left: 20px; display: inline-block">'+ remarkArray[i][1] +'</div></li>');
            }

            /**
             * @since 2024-09-04 渲染div，显示
             */
            $("#cn-leetcode-remark").html('<ul>'+ remarkHtmlArray.join('') +'</ul>');
            $("#cn-leetcode-level").html(levelHtml);
            $("#cn-leetcode-level").show();

            /**
             * @since 2024-09-04 监听按钮，显示说明div
             */
            $("#cn-leetcode-level").on("mouseenter", function() {
                /**
                 * @since 2024-09-04 定位div
                 */
                let offset = $("#cn-leetcode-level").offset();
                $("#cn-leetcode-remark").css({
                    top: offset.top+28,
                    left: offset.left,
                });
                $("#cn-leetcode-remark").fadeIn();
            });
            $("#cn-leetcode-level").on("mouseleave", function() {
                setTimeout(function (){
                    $("#cn-leetcode-remark").fadeOut();
                }, 200);
            });
            ConsoleLog("等级，加载成功");
        } else {
            ConsoleLog("等级，存在");
        }
    } else {
        /**
         * @since 2024-07-24 页面未加载成功，稍后再试
         */
        ConsoleLog("等级，未加载成功，等待");
        // setTimeout(ShowLevel, 200, problemLevel, times-1);
    }
    setTimeout(ShowLevel, 200, problemLevel, times-1);
}

/**
 * @title 更新等级数据
 * @author start2004
 * @since 2024-07-25
 */
async function UpdateLevel(){
    /**
     * @since 2024-09-04 获取数据
     */
    const levelUrl = "https://raw.githubusercontent.com/start2004/leetcode_score_json/main/level.json";
    let levelData = await FetchJson(levelUrl);
    if(levelData === null) return false;

    /**
     * @since 2024-09-04 更新缓存
     */
    const levelObject = {
        "date": Date(),
        "time": Date.now(),
        "data": levelData
    };
    await SetStorage(LEVEL_KEY, levelObject);
    ConsoleLog("等级，数据更新成功");
    return true;
}

/**
 * ===============================================================
 * 分隔符
 * ===============================================================
 */

/**
 * @title 获取url的json数据
 * @author start2004
 * @since 2024-09-03
 *
 * @param {string} url 数据接口url
 * @return Object
 */
async function FetchJson(url) {
    try {
        const response = await fetch(url);

        // 检查响应是否是有效的 HTTP 响应
        if (!response.ok) {
            // throw new Error(`HTTP error! status: ${response.status}`);
            ConsoleLog("HTTP error! status: "+ response.status);
            return {};
        } else {}

        const data = await response.json();
        return data;
    } catch (error) {
        // console.error('Error fetching JSON:', error);
        ConsoleLog('Error fetching JSON:', error);
        return {}; // 或者根据需求处理错误
    }
}

/**
 * @title 更新缓存
 * @author start2004
 * @since 2024-08-14
 *
 * @param  {string} key 键值
 * @param {mixed} data 缓存数据
 */
function SetStorage(key, value) {
    return new Promise((resolve, reject) => {
        chrome.storage.local.set({ [key]: value }, () => {
            if (chrome.runtime.lastError) {
                reject(chrome.runtime.lastError);
            } else {
                resolve();
            }
        });
    });
}

/**
 * @title 获取缓存
 * @author start2004
 * @since 2024-08-14
 *
 * @param {string} key 缓存键值
 * @return {mixed} 键值对应数据
 */
function GetStorage(key) {
    return new Promise((resolve, reject) => {
        chrome.storage.local.get(key, (result) => {
            if (chrome.runtime.lastError) {
                reject(chrome.runtime.lastError);
            } else {
                resolve(result[key]);
            }
        });
    });
}

/**
 * @title 控制台打印信息
 * @author start2004
 * @since 2024-09-03
 *
 * @param {mixed} args 打印信息
 */
function ConsoleLog(...args){
    if(DEV){
        console.log("%c"+chrome.i18n.getMessage("extension_name"), "color: #E0E0E0; background-color: #121212; margin: 5px; padding: 3px", ...args);
    } else {}
}